package main

import (
	"log"
	"sync"
	"time"
)

// select + channel
// 示例：实现不阻塞的情况下，读写 channel
// 这个方法有个问题：会改变 channel 的状态，channel 必须接受一个值或者向它发送一个值

func trySend(c chan<- int, val int) bool {
	select {
	case c <- val:
		return true
	default: // 其它分支都因 channel 堵塞时，select 会选择 default 分支执行
		return false
	}
}

func tryRecv(c <-chan int) (int, bool) {
	select {
	case val := <-c:
		return val, true
	default:
		return 0, false
	}
}

func producer(c chan<- int) {
	var i int = 1
	for {
		time.Sleep(2 * time.Second)

		// 每隔2秒向 channel 发送值
		ok := trySend(c, i)

		// 如果缓冲区未满，则发送成功，i++
		if ok {
			log.Printf("[producer] send %d to channel\n", i)
			i++
			continue
		}

		log.Printf("[producer] try to send %d but channel is full", i)
	}
}

func consumer(c <-chan int) {
	for {
		val, ok := tryRecv(c)
		if !ok {
			log.Printf("[consumer] try to consume but channel is empty")

			time.Sleep(1 * time.Second)

			continue
		}

		log.Printf("[consumer] recv value %d from channel", val)

		if val >= 3 {
			log.Println("[consumer]: exit")
			return
		}
	}
}

func main() {
	var wg sync.WaitGroup
	wg.Add(2)

	ch := make(chan int, 3)
	// log.Printf("channel cap is: %d", cap(ch))

	go func() {
		producer(ch)
		wg.Done()
	}()

	go func() {
		consumer(ch)
		wg.Done()
	}()

	wg.Wait()

}
